package ch7.DiningPhilosophers;

import util.Debug;

import javax.swing.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class BuggyLckBasedPhilosopher extends AbstractPhilosopher{
    /**
     * 为确保每个Chopstic实例有且仅有一个显示锁与之对应，这里的map必须采用statci修饰
     */
    protected final static ConcurrentMap<Chopstick, ReentrantLock> LOCK_MAP;
    static {
        LOCK_MAP = new ConcurrentHashMap<Chopstick, ReentrantLock>();
    }

    public BuggyLckBasedPhilosopher(int id, Chopstick left, Chopstick right) {
        super(id, left, right);
        // 每个筷子对应一个唯一的锁实例
        LOCK_MAP.putIfAbsent(left, new ReentrantLock());
        LOCK_MAP.putIfAbsent(right, new ReentrantLock());
    }

    @Override
    public void eat() {
        // 先拿起左手筷子，再拿起右手筷子
        if (pickUpChopstick(left) && pickUpChopstick(right)) {
            // 同时拿起两个筷子才可吃饭
            try {
                doEat();
            } finally {
                putDownChopsticks(left, right);
            }
        }
    }

    protected boolean pickUpChopstick(Chopstick chopstick) {
        final ReentrantLock lock = LOCK_MAP.get(chopstick);
        lock.lock();
        try {
            Debug.info("%s is picking up %s on his %s...%n", this, chopstick, chopstick == left ? "left" : "right");
            chopstick.pickUp();
        } catch (Exception e) {
            e.printStackTrace();
            lock.unlock();
            return false;
        }
        return true;
    }


    private void putDownChopsticks(Chopstick chopstick1, Chopstick chopstick2) {
        try {
            putDownChopstick(chopstick1);
        } finally {
            putDownChopstick(chopstick2);
        }
    }

    protected void putDownChopstick(Chopstick chopstick) {
        final ReentrantLock lock = LOCK_MAP.get(chopstick);
        try {
            Debug.info("%s is putting down %s on this %s...%n", this, chopstick, chopstick == left ? "left" : "right");
            chopstick.putDown();
        } finally {
            lock.unlock();
        }
    }
}
